package com.tyanxie.asd.activity

import android.Manifest
import android.app.Dialog
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import android.view.*
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.lifecycle.ViewModelProvider
import androidx.room.Room
import com.chaquo.python.Python
import com.tyanxie.asd.Constant
import com.tyanxie.asd.R
import com.tyanxie.asd.config.IDataBase
import com.tyanxie.asd.databinding.ActivityDataPanelBinding
import com.tyanxie.asd.databinding.ChoicePhotoModeDialogBinding
import com.tyanxie.asd.databinding.MeasureCompleteDialogBinding
import com.tyanxie.asd.fragment.ProgressDialogFragment
import com.tyanxie.asd.model.PhotoSugar
import com.tyanxie.asd.model.Sugar
import com.tyanxie.asd.model.SugarEntity
import com.tyanxie.asd.model.SugarNumber
import com.tyanxie.asd.util.Uri2PathUtils
import com.tyanxie.asd.viewmodel.PhotoSugarListViewModel
import java.io.File
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.*
import java.util.concurrent.Executors


/**
 * 数据面板页
 */
class DataPanelActivity : AppCompatActivity() {
    companion object {
        const val TAG = "DataPanelActivity"
    }

    // ViewBinding
    private lateinit var binding: ActivityDataPanelBinding

    // 加载中对话框
    private val progressDialog = ProgressDialogFragment(R.string.calculating)

    // 用户当前选择的苹果类型idx
    private var choice: Int = 0

    // 用户当前点击的按钮idx
    private var currentIdx = 0

    // 糖度模型列表
    private lateinit var photoSugars: List<PhotoSugar>

    // 糖度模型ViewModel
    private lateinit var photoSugarListViewModel: PhotoSugarListViewModel

    /**
     * 拍照启动器
     */
    private val takePhotoLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) {
        if (!it) {
            // 拍摄失败, 直接返回
            return@registerForActivityResult
        }
        // 计算糖度
        computeSugar()
    }

    /**
     * 获取相册图片启动器
     */
    private val getPhotoLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        // 获取用户选择的图片的uri
        val uri = it.data?.data
        if (uri == null) {
            runOnUiThread {
                Toast.makeText(this, getString(R.string.get_photo_failed), Toast.LENGTH_SHORT).show()
            }
            return@registerForActivityResult
        }
        // 将uri转为绝对路径
        val path = Uri2PathUtils.getRealPathFromUri(this, uri)
        if (path == null) {
            runOnUiThread {
                Toast.makeText(this, getString(R.string.get_photo_failed), Toast.LENGTH_SHORT).show()
            }
            return@registerForActivityResult
        }
        // 设置file
        setFile(File(path))
        // 计算糖度
        computeSugar()
    }

    /**
     * 获取相机权限启动器, 在获取之后会重新尝试拍照
     */
    private val requestTakePhotoPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            runOnUiThread {
                if (it) {
                    takePhoto()
                } else {
                    Toast.makeText(
                        this,
                        getString(R.string.need_take_photo_permission),
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }

    /**
     * 获取相册权限启动器, 在获取之后会重新尝试获取图片
     */
    private val requestGetPhotoPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            runOnUiThread {
                if (it) {
                    getPhoto()
                } else {
                    Toast.makeText(
                        this,
                        getString(R.string.need_get_photo_permission),
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }

    /**
     * 计算糖度
     */
    private fun computeSugar() {
        // 获取当前sugar
        val photoSugar = photoSugars[currentIdx]
        // 获取uri
        val file = photoSugar.sugar.file
        // 判断是否发生错误
        if (file == null) {
            // 发生了未知错误则报错并返回
            runOnUiThread {
                Toast.makeText(this, getString(R.string.unknown_error), Toast.LENGTH_SHORT).show()
            }
            return
        }
        Log.d(TAG, "computeSugar: ${file.absolutePath}")

        // 展示加载框
        progressDialog.show(supportFragmentManager, ProgressDialogFragment.TAG)
        // 调用py文件进行运算
        Executors.newFixedThreadPool(1).execute {
            try {
                val res = Python.getInstance().getModule("script")["compute"]
                    ?.call(choice, file.absolutePath)
                    ?.toDouble()
                // 转为BigDecimal对象并设置
                photoSugar.sugar.sugarVal = BigDecimal("$res")
                runOnUiThread { photoSugarListViewModel.sugarMutableLiveData.postValue(photoSugars) }
            } catch (e: Exception) {
                runOnUiThread {
                    Toast.makeText(this, getString(R.string.calculation_failed), Toast.LENGTH_SHORT)
                        .show()
                }
                Log.d(TAG, "计算失败: ${e.localizedMessage}")
                // 重置结果
                photoSugar.sugar.sugarVal = null
                return@execute
            } finally {
                // 运算完成后关闭dialog
                runOnUiThread {
                    progressDialog.dismiss()
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 获取传入的内容
        if (intent.extras == null) {
            // 页面意外打开
            Toast.makeText(this, getString(R.string.unknown_error), Toast.LENGTH_SHORT).show()
            Log.e(TAG, "页面被意外打开")
            finish()
            return
        }
        // 获取用户选择的苹果类型idx
        choice = intent.extras!!.getInt(Constant.CHOICE_KEY)
        // 获取viewBinding
        binding = ActivityDataPanelBinding.inflate(layoutInflater)
        // 设置ContextView
        setContentView(binding.root)
        // 初始化数据
        initData()
    }

    /**
     * 初始化数据
     */
    private fun initData() {
        // 设置当前种类文本
        val type = getString(Constant.apples[choice])
        binding.adpCurtypeTv.text = getString(R.string.current_type, type)

        // 完成按钮点击事件
        binding.adpCompleteBtn.setOnClickListener {
            // 获取数据库
            val database = Room.databaseBuilder(this, IDataBase::class.java, "sugar")
                .allowMainThreadQueries()
                .build()
            val sugarNumberDao = database.sugarNumberDao()
            val sugarEntityDao = database.sugarEntityDao()

            // 保存数据
            val sugarNumber = SugarNumber(id = null, createTime = Date().time, type = choice)
            val id = sugarNumberDao.save(sugarNumber)
            sugarEntityDao.saveAll(
                SugarEntity(
                    id = null,
                    path = photoSugars[0].sugar.file!!.path,
                    value = photoSugars[0].sugar.sugarVal!!.toEngineeringString(),
                    sugarNumberId = id
                ),
                SugarEntity(
                    id = null,
                    path = photoSugars[1].sugar.file!!.path,
                    value = photoSugars[1].sugar.sugarVal!!.toEngineeringString(),
                    sugarNumberId = id
                ),
                SugarEntity(
                    id = null,
                    path = photoSugars[2].sugar.file!!.path,
                    value = photoSugars[2].sugar.sugarVal!!.toEngineeringString(),
                    sugarNumberId = id
                ),
                SugarEntity(
                    id = null,
                    path = photoSugars[3].sugar.file!!.path,
                    value = photoSugars[3].sugar.sugarVal!!.toEngineeringString(),
                    sugarNumberId = id
                ),
                SugarEntity(
                    id = null,
                    path = photoSugars[4].sugar.file!!.path,
                    value = photoSugars[4].sugar.sugarVal!!.toEngineeringString(),
                    sugarNumberId = id
                )
            )
            // 展示完成对话框
            showCompleteDialog()
        }

        // 获取并设置viewModel
        photoSugarListViewModel = ViewModelProvider(
            this, ViewModelProvider.AndroidViewModelFactory(application)
        ).get(PhotoSugarListViewModel::class.java)
        if (photoSugarListViewModel.sugarMutableLiveData.value == null) {
            photoSugars = mutableListOf(
                PhotoSugar(binding.adpPhotoBtn, Sugar()),
                PhotoSugar(binding.adpPhotoBtn2, Sugar()),
                PhotoSugar(binding.adpPhotoBtn3, Sugar()),
                PhotoSugar(binding.adpPhotoBtn4, Sugar()),
                PhotoSugar(binding.adpPhotoBtn5, Sugar()),
            )
            photoSugarListViewModel.sugarMutableLiveData.value = photoSugars
        } else {
            // ViewModel中已经有数据, 但是需要修改button对象
            photoSugars = photoSugarListViewModel.sugarMutableLiveData.value!!
            photoSugars[0].button = binding.adpPhotoBtn
            photoSugars[1].button = binding.adpPhotoBtn2
            photoSugars[2].button = binding.adpPhotoBtn3
            photoSugars[3].button = binding.adpPhotoBtn4
            photoSugars[4].button = binding.adpPhotoBtn5
            photoSugarListViewModel.sugarMutableLiveData.value = photoSugars
        }
        // ViewModel配置事件监听
        photoSugarListViewModel.sugarMutableLiveData.observe(this) {
            for ((i, ps) in it.withIndex()) {
                runOnUiThread {
                    ps.button.apply {
                        if (ps.sugar.sugarVal != null) { // 已测糖度
                            // isEnabled = false
                            text = getString(
                                R.string.btn_suger_is,
                                ps.sugar.sugarVal!!.setScale(1, RoundingMode.HALF_UP).toString()
                            )
                        } else { // 未测糖度
                            text = getString(R.string.btn_take_number_photo, i + 1)
                        }
                        // 按钮点击事件
                        setOnClickListener {
                            // 设置当前点击的按钮
                            currentIdx = i
                            // 展示选择图片方式的对话框
                            showChoicePhotoModeDialog()
                        }
                    }
                }
            }
            // 更新平均值和完成测量按钮
            updateCompleteBtn()
        }
    }

    /**
     * 调用相机进行拍照
     */
    private fun takePhoto() {
        if (ContextCompat.checkSelfPermission(
                this, Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // 没有权限则先获取权限
            requestTakePhotoPermissionLauncher.launch(Manifest.permission.CAMERA)
        } else {
            // 获取存储目标文件
            val file = getImageFile()
            // 根据File对象生成Uri对象
            val uri = FileProvider.getUriForFile(
                this@DataPanelActivity, Constant.FILE_PROVIDER_AUTHORITIES, file
            )
            if (uri == null) {
                // 获取拍照路径失败
                Log.e(TAG, "Uri为null, file=$file")
                runOnUiThread {
                    Toast.makeText(
                        this@DataPanelActivity, getString(R.string.unknown_error), Toast.LENGTH_SHORT
                    ).show()
                }
                return
            }
            // 将uri设置进入sugar对象
            setFile(file)
            // 调用拍照并保存
            takePhotoLauncher.launch(uri)
        }
    }

    /**
     * 设置图像uri, 会设置currentIdx对应的photoSugar对象的uri
     */
    private fun setFile(file: File) {
        runOnUiThread {
            photoSugars[currentIdx].sugar.file = file
            photoSugarListViewModel.sugarMutableLiveData.postValue(photoSugars)
        }
    }

    /**
     * 从相册中获取图片
     */
    private fun getPhoto() {
        if (ContextCompat.checkSelfPermission(
                this, Manifest.permission.READ_EXTERNAL_STORAGE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // 没有权限则先获取权限
            requestGetPhotoPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
        } else {
            getPhotoLauncher.launch(Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI))
        }
    }

    /**
     * 获取存储的目标文件
     */
    private fun getImageFile(): File {
        val filename = "${getString(R.string.app_name)}_${System.currentTimeMillis()}"
        val dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        return File.createTempFile(filename, ".jpg", dir)
    }

    /**
     * 更新平均值和完成测量按钮
     * 如果还没有数据就设置为`-.-`, 否则设置为计算结果, 保留两位小数
     * 如果数据量为3则将完成测量按钮设置为可使用
     */
    private fun updateCompleteBtn() {
        // 数据个数
        var count = 0
        // 遍历数组
        photoSugars.forEach {
            if (it.sugar.sugarVal != null) {
                count++
            }
        }
        // 设置完成测量按钮是否可点击
        runOnUiThread { binding.adpCompleteBtn.isEnabled = (count == 5) }
    }

    /**
     * 展示选择图片获取方式的对话框
     */
    private fun showChoicePhotoModeDialog() {
        val cpmd = ChoicePhotoModeDialogBinding.inflate(layoutInflater)
        val dialog = Dialog(this, R.style.BottomDialog)
        //初始化视图
        cpmd.cpmdCancelBtn.setOnClickListener {
            dialog.dismiss()
        }
        cpmd.cpmdGetPhotoBtn.setOnClickListener {
            getPhoto()
            dialog.dismiss()
        }
        cpmd.cpmdTakePhotoBtn.setOnClickListener {
            takePhoto()
            dialog.dismiss()
        }
        dialog.setContentView(cpmd.root)
        val dialogWindow: Window = dialog.window!!
        dialogWindow.setGravity(Gravity.BOTTOM)
        // 获取对话框当前的参数值
        val lp: WindowManager.LayoutParams = dialogWindow.attributes
        // 设置宽度
        lp.width = resources.displayMetrics.widthPixels
        dialogWindow.attributes = lp
        dialog.show()
    }

    /**
     * 展示完成测量对话框
     */
    private fun showCompleteDialog() {
        val mcd = MeasureCompleteDialogBinding.inflate(layoutInflater)
        val dialog = AlertDialog.Builder(this).setView(mcd.root).create()
        // submit按钮
        mcd.mcdSubmitBtn.setOnClickListener {
            dialog.dismiss()
            finish()
        }
        dialog.show()
    }
}